package edu.bu.met683.TravelDroid;

import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

import android.app.AlertDialog;
import android.app.ListActivity;
import android.app.ProgressDialog;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.DialogInterface.OnClickListener;
import android.location.Criteria;
import android.location.Location;
import android.location.LocationManager;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;

import com.google.android.maps.GeoPoint;

import edu.bu.met683.TravelDroid.data.DataUtilities;
import edu.bu.met683.TravelDroid.data.SortByProximity;
import edu.bu.met683.TravelDroid.data.Tour;


public class TourList extends ListActivity
{
	public static final Double METERS_IN_A_MILES = 1609.344;
	
	public List<Tour> tours;
	private TextView noTours;
	private TourListAdapter tourListAdapter;
	private TravelDroidApplication application;
	private Location myLocation;
	public static final int CLOSE_MENU_ID = 1;
	//private static final int GENERATING_MAP_DIALOG_KEY = 0;
	private LocationManager locationManager;
	private ProgressDialog progressDialog = null;
	
	/**
	 * This method is executed when the user selects a tour.
	 */
	@Override
	protected void onListItemClick(final ListView l, final View v, final int position, final long id)
	{
		try
		{
			application = (TravelDroidApplication) this.getApplication();
			application.SetCurrentTour(tours.get(position)); 
			Intent intent = new Intent(Constants.TOUR_MAP_AND_STATS_SCREEN);
			this.startActivityForResult(intent, 0);			
			finish();
		}
		catch(Exception e)
		{
			Log.e("ERROR", "ERROR IN CODE TourList onListItemClick:"+e.toString());
		}		
	}

	/**
	 * This method when the MapActivy completes
	 */
	protected void onActivityResult(int requestCode, int resultCode, Intent data) 
	{
    }


	/**
	 * Handler to handle populating the Tourlistview
	 */
	private final Handler handler = new Handler() {  
	      @Override 	  
	        public void handleMessage(final Message msg) { 
	    	  try
	    	  {
	            if ((tours == null) || (tours.size() == 0)) 
	            { 
	      		  application = (TravelDroidApplication) getApplication();
	    		  TourList.this.noTours = (TextView) findViewById(R.id.noAdjacentTours);
	    		  TourList.this.noTours.setText("No tours found within " + Integer.toString(application.GetTourStartDistanceRange()) + " miles.");
	            } 
	            else 
	            { 
	            	TourList.this.tourListAdapter = new TourListAdapter(TourList.this, tours); 
	            	TourList.this.setListAdapter(tourListAdapter); 
	            } 
	    	  }
	    	  catch(Exception ee)
	    	  {
	    		  Log.e("ERROR", "ERROR IN CODE TourList handler:"+ee.toString());
	    	  }
	       } 
	    }; 
	

	@Override
	public void onCreate(Bundle savedInstanceState) {
	  super.onCreate(savedInstanceState);
	  try
	  {
		  this.myLocation = GetCurrentLocation();
		  if(null != myLocation)
		  {
		  		tours = new ArrayList<Tour>();
		  		this.setContentView(R.layout.tourviewlist);
		  		//this.SetDefaultApplicationValues();
	  
		  		final ListView listView = this.getListView(); //gets the activities listview widget
		  		listView.setItemsCanFocus(false);
		  		listView.setChoiceMode(ListView.CHOICE_MODE_SINGLE);
		  		listView.setEmptyView(noTours); //sets the view to show if the list is empty
		  		getListView().setTextFilterEnabled(true);
		  }
	  }
	  catch(Exception ee)
	  {
		  Log.e("ERROR", "ERROR IN CODE TourList onCreate:"+ee.toString());
	  }
	}
	
	
    @Override 
    protected void onResume() { 
    	try
    	{
    		super.onResume(); 
            progressDialog = new ProgressDialog(this);
            progressDialog.setTitle("TravelDroid");
            progressDialog.setMessage("Loading Tours...");
            progressDialog.setIndeterminate(true);
            progressDialog.setCancelable(false);

            Thread populateThread = new Thread(){
            		public void run()
            		{
            			PopulateNearByTours();
            			progressDialog.dismiss();
            		}};
            populateThread.start();
            progressDialog.show();
        	
    	}
  	  	catch(Exception ee)
  	  	{
  	  		Log.e("ERROR", "ERROR IN CODE:"+ee.toString());
  	  	}
  	} 

	/**
	 * Loads the tour data, determines the distance from the starting point to the users current location.
	 * It also populate the listview with the nearby tours
	 */
	private int PopulateNearByTours()
	{
		/*
		try {
			Thread.currentThread().sleep(5000);
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		*/
		try
		{	
			tours = Tour.loadTourData(this.getResources());
			//calculate the distance from the current location of the device to each of the tours
			if(tours.size() > 0)
			{
				//Location myLocation = null;				
				if(null != myLocation)
				{
					for(Tour thisTour : tours)
					{
						GeoPoint tourLocation = thisTour.getStartPoint();
						double lat = tourLocation.getLatitudeE6()/Constants.IE6;
						double lon = tourLocation.getLongitudeE6()/Constants.IE6;
						Location startLocation = new Location("");
						startLocation.setLatitude(lat);
						startLocation.setLongitude(lon);
						float distance = myLocation.distanceTo(startLocation); //distance is in meters!
						thisTour.setProximity(DataUtilities.ConvertMetersToMiles(distance));						
					}
				}
				Collections.sort(tours, new SortByProximity());
				TourList.this.handler.sendEmptyMessage(0);
				return tours.size();
			}
			TourList.this.handler.sendEmptyMessage(0);
			return tours.size();
		}
		catch(Exception ee)
		{
			Log.e("ERROR", "ERROR IN CODE:"+ee.toString());
			return 0;
		}
	}
	/**
	 * Obtains the users current gps location
	 */
	private Location GetCurrentLocation()
	{
		Location myLocation = null;
		try
		{
			
			locationManager = (LocationManager)getSystemService(Context.LOCATION_SERVICE);
			if(null == locationManager)
			{
				LocationNotFound("No GPS device found.");
			}
			else
			{
				Criteria criteria = new Criteria();
				criteria.setAccuracy(Criteria.ACCURACY_FINE);
				criteria.setAltitudeRequired(false);
				criteria.setBearingRequired(false);
				criteria.setCostAllowed(true);
				criteria.setPowerRequirement(Criteria.POWER_LOW);

				String locationProvider = locationManager.getBestProvider(criteria, true);
				myLocation = locationManager.getLastKnownLocation(locationProvider);
				if (null == myLocation)
				{
					//try other providers to see if location can be obtained.
					List<String> providers = locationManager.getProviders(true);
					if(providers.size() > 0)
					{
						for(String provider : providers)
						{
							myLocation = locationManager.getLastKnownLocation(provider);
							if(null != myLocation)
								break;
						}
					}		
					if(null == myLocation)
					{
						LocationNotFound("Can not locate current position.");
					}
				}
			}
			return myLocation;
		}
		catch(Exception e)
		{
			Log.e("Error in GetCurrentLocation","could not obtain current location");
			return null;
		}
	}
	
	/**
	 * Generates an alert dialog when gps cannot determine current locaiton
	 */
	
	private final void LocationNotFound(String message)
	{		   

	new AlertDialog.Builder(this)
	    .setMessage(message)
	    .setPositiveButton("Exit", new OnClickListener() 
		      						   {
	    									public void onClick( DialogInterface arg0, int arg1) 
	    									{
												finish();
											}
		    	  						})
		.show(); 
	}
	
    
	/**
	 * creates the menu
	 */
	public boolean onCreateOptionsMenu(Menu menu) {
		menu.add(0, CLOSE_MENU_ID, 0, "Close TravelDroid");
		return true;
	}

	/**
	 * Handles item selections
	 */
	public boolean onOptionsItemSelected(MenuItem item) 
	{
		switch (item.getItemId()) 
		{

			case CLOSE_MENU_ID:
				finish();
				return true;
		}
		return false;
	}

}
 

